package org.dromara.web.service.impl

import cn.dev33.satoken.stp.StpUtil
import io.github.oshai.kotlinlogging.KotlinLogging
import org.dromara.common.core.domain.model.LoginUser
import org.dromara.common.core.domain.model.SmsLoginBody
import org.dromara.common.core.enums.LoginType
import org.dromara.common.core.utils.ValidatorUtils.validate
import org.dromara.common.json.utils.JsonUtils
import org.dromara.common.satoken.utils.LoginHelper
import org.dromara.common.tenant.helper.TenantHelper
import org.dromara.system.domain.SysUser
import org.dromara.system.domain.vo.SysClientVo
import org.dromara.system.mapper.SysUserMapper
import org.dromara.web.domain.vo.LoginVo
import org.dromara.web.service.IAuthStrategy
import org.dromara.web.service.SysLoginService
import org.springframework.stereotype.Service

/**
 * 短信认证策略
 *
 *@author LikeYouDo
 *@date 2025/1/3 15:54
 */
@Service("sms" + IAuthStrategy.BASE_NAME)
class SmsAuthStrategy(
    private val loginService: SysLoginService,
    private val userMapper: SysUserMapper,
) : IAuthStrategy {

    companion object {
        private val log = KotlinLogging.logger {}
    }

    override fun login(body: String, client: SysClientVo): LoginVo {
        val loginBody = JsonUtils.parseObject(body, SmsLoginBody::class.java)
        validate(loginBody)
        val tenantId = loginBody.tenantId
        val phonenumber = loginBody.phonenumber
        val smsCode = loginBody.smsCode
        val loginUser = TenantHelper.dynamic<LoginUser>(tenantId) {
            val user = loadUserByCondition(userMapper, SysUser::getPhonenumber, phonenumber, log)
            loginService.checkLogin(LoginType.SMS, tenantId, user.userName) {
                !validateCode(loginService, tenantId, phonenumber, smsCode)
            }
            loginService.buildLoginUser(user)
        }.apply {
            clientKey = client.clientKey
            deviceType = client.deviceType
        }
        val model = createSaLoginModel(client)
        // 生成token
        LoginHelper.login(loginUser, model)

        return LoginVo().apply {
            accessToken = StpUtil.getTokenValue()
            expireIn = StpUtil.getTokenTimeout()
            clientId = client.clientId
        }
    }

}
